﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Linq.Expressions;
using System.Web.Routing;

namespace MTO.Framework.Web.Mvc.Html
{
    public static class LabelExtensions
    {
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
        {
            return LabelFor(htmlHelper, expression, new RouteValueDictionary(htmlAttributes));
        }

        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();

            if (String.IsNullOrEmpty(labelText))
            {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");

            tag.MergeAttributes(htmlAttributes);
            tag.Attributes.Add("for", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);

            return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
        }

        /// <summary>
        /// Retourne un libellé HTML concaténé avec le caractère ":" à la fin.
        /// </summary>
        /// <param name="html"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static MvcHtmlString DisplayLabel(this HtmlHelper html, string expression)
        {
            var label = System.Web.Mvc.Html.LabelExtensions.Label(html, expression);
            MvcHtmlString displayLabel = MvcHtmlString.Create(string.Format("{0} :", label.ToString()));

            return displayLabel;
        }

        /// <summary>
        /// Retourne un libellé HTML concaténé avec le caractère ":" à la fin.
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static MvcHtmlString DisplayLabelFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
        {
            var label = System.Web.Mvc.Html.LabelExtensions.LabelFor<TModel, TValue>(htmlHelper, expression);
            MvcHtmlString displayLabel = MvcHtmlString.Create(string.Format("{0} :", label.ToString()));

            return displayLabel;
        }

        /// <summary>
        /// Retourne un libellé HTML concaténé avec le caractère ":" à la fin.
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static MvcHtmlString DisplayLabelFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
        {
            var label = LabelFor<TModel, TValue>(htmlHelper, expression, htmlAttributes);
            MvcHtmlString displayLabel = MvcHtmlString.Create(string.Format("{0} :", label.ToString()));

            return displayLabel;
        }

        /// <summary>
        /// Retourne un libellé HTML contenant un indicateur de champ requis ainsi que le caractère ":" à la fin.
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static MvcHtmlString EditorLabel(this HtmlHelper htmlHelper, string expression)
        {
            return EditorLabelHelper(htmlHelper, ModelMetadata.FromStringExpression(expression, htmlHelper.ViewData), ExpressionHelper.GetExpressionText(expression), null);
        }

        /// <summary>
        /// Retourne un libellé HTML contenant un indicateur de champ requis ainsi que le caractère ":" à la fin.
        /// </summary>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>

        public static MvcHtmlString EditorLabel(this HtmlHelper htmlHelper, string expression, object htmlAttributes)
        {
            return EditorLabelHelper(htmlHelper, ModelMetadata.FromStringExpression(expression, htmlHelper.ViewData), ExpressionHelper.GetExpressionText(expression), new RouteValueDictionary(htmlAttributes));
        }

        /// <summary>
        /// Retourne un libellé HTML contenant un indicateur de champ requis ainsi que le caractère ":" à la fin.
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static MvcHtmlString EditorLabelFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression)
        {
            return EditorLabelHelper(htmlHelper, ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData), ExpressionHelper.GetExpressionText(expression), null);
        }

        /// <summary>
        /// Retourne un libellé HTML contenant un indicateur de champ requis ainsi que le caractère ":" à la fin.
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="htmlHelper"></param>
        /// <param name="expression"></param>
        /// <param name="htmlAttributes"></param>
        /// <returns></returns>
        public static MvcHtmlString EditorLabelFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
        {
            return EditorLabelHelper(htmlHelper, ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData), ExpressionHelper.GetExpressionText(expression), new RouteValueDictionary(htmlAttributes));
        }

        internal static MvcHtmlString EditorLabelHelper(HtmlHelper htmlHelper, ModelMetadata metadata, string htmlFieldName, IDictionary<string, object> htmlAttributes)
        {
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();

            if (String.IsNullOrEmpty(labelText))
            {
                return MvcHtmlString.Empty;
            }

            StringBuilder inputItemBuilder = new StringBuilder();

            // Construction du tag Label
            TagBuilder tagLabel = new TagBuilder("label");
            tagLabel.MergeAttributes(htmlAttributes);
            tagLabel.Attributes.Add("for", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tagLabel.SetInnerText(labelText);

            if (metadata.IsRequired)
            {
                // Construciton du tag Em
                TagBuilder tagEm = new TagBuilder("em");
                tagEm.SetInnerText("*");

                tagLabel.InnerHtml += tagEm.ToString(TagRenderMode.Normal);
            }

            // Ajouter le ":" à la fin du Label
            tagLabel.InnerHtml += " :";

            // Imprimer le tag Label
            inputItemBuilder.Append(tagLabel.ToString(TagRenderMode.Normal));

            return MvcHtmlString.Create(inputItemBuilder.ToString());
        }
    }
}
